home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_10_11 / crdtools.c < prev    next >
Text File  |  1992-06-16  |  18KB  |  533 lines

  1. /*  CRDTOOLS.C : Tools to exercise CORDIC calculations for sine/cosine.
  2.  *   Make in Borland C++'s internal environment.
  3.  *   (c) 1991 Michael Bertrand.
  4.  */
  5.  
  6. #include <stdio.h>  /* printf, scanf */
  7. #include <math.h>   /* sqrt, atan, sin, cos, fabs */
  8. #include <conio.h>  /* clrscr, gotoxy, getch, cputs, etc. */
  9. #include <dos.h>    /* struct time, gettime */
  10.  
  11. typedef unsigned int WORD;
  12. typedef struct time TIME;
  13.  
  14. typedef struct
  15. {
  16.   int x;
  17.   int y;
  18. } POINT;
  19.  
  20. typedef struct
  21. {
  22.   double u;
  23.   double v;
  24. } DOUB_PT;
  25.  
  26. char Menu(void);
  27. void SingleAngleDegree(void);
  28. void SingleAngleCordic(void);
  29. void ListSeries(void);
  30. void CalcStatistics(void);
  31. void TimeTest(void);
  32. int  HundSecs(TIME *tp, TIME *sp);
  33. void CalcHexPtsCLib(POINT center, POINT vertex);
  34. void CalcHexPtsCORDIC(POINT center, POINT vertex);
  35. void SinCosSetup(void);
  36. void SinCos(WORD theta, int *sin, int *cos);
  37.  
  38. #define TRUE  1
  39. #define ESC   0x1B
  40.  
  41. /* Quadrants for angles. */
  42. #define QUAD1 1
  43. #define QUAD2 2
  44. #define QUAD3 3
  45. #define QUAD4 4
  46.  
  47. /* NBITS is number of bits used for CORDIC units. */
  48. #define NBITS 14
  49.  
  50. /* NUM_PTS is number of vertices in polygon. */
  51. #define NUM_PTS 6
  52.  
  53. /* Macros to convert angles to different units. */
  54. #define DEG_TO_CORDIC(x) ((WORD) ((double)x/90.0*CordicBase + 0.5))
  55. #define DEG_TO_RADIAN(x) (x/180.0*M_PI)
  56. #define CORDIC_TO_RADIAN(x) ((double)x/CordicBase*M_PI/2)
  57.  
  58. /* NUM_TIMES is number of times to iterate for timing test. */
  59. #define NUM_TIMES 1000
  60.  
  61. int  ArcTan[NBITS];      /* angular constants : arctans */
  62. int  xInit;              /* initial x projection */
  63. WORD CordicBase;         /* base for CORDIC units */
  64. WORD HalfBase;           /* CordicBase / 2 */
  65. WORD Quad2Boundary;      /* 2 * CordicBase */
  66. WORD Quad3Boundary;      /* 3 * CordicBase */
  67. POINT HexPts[NUM_PTS+1]; /* to hold calculated polygon points */
  68.  
  69. void main(void)
  70. {
  71.   SinCosSetup();
  72.  
  73.   do
  74.     {
  75.     switch(Menu())
  76.       {
  77.       case '1' : case 'd':  case 'D':
  78.         SingleAngleDegree();
  79.         break;
  80.       case '2' : case 'c':  case 'C':
  81.         SingleAngleCordic();
  82.         break;
  83.       case '3' : case 'l':  case 'L':
  84.         ListSeries();
  85.         break;
  86.       case '4' : case 's':  case 'S':
  87.         CalcStatistics();
  88.         break;
  89.       case '5' : case 't':  case 'T':
  90.         TimeTest();
  91.         break;
  92.       case '6' : case 'q':  case 'Q':
  93.         clrscr();
  94.         return;
  95.       }  /* switch */
  96.     } while (TRUE);
  97. }
  98.  
  99. char Menu(void)
  100. /*
  101.    USE  : Display menu and get user choice.
  102.    RET  : User choice.
  103. */
  104. {
  105.   struct text_info ti;    /* to get default text color */
  106.  
  107.   gettextinfo(&ti);
  108.   clrscr();
  109.   textattr(LIGHTGRAY);
  110.   gotoxy(26, 1); cputs("╔═════ CORDIC Tests ═════╗");
  111.   gotoxy(26, 2); cputs("║                        ║");
  112.   gotoxy(26, 3); cputs("║  1) One Angle (Degree) ║");
  113.   gotoxy(26, 4); cputs("║                        ║");
  114.   gotoxy(26, 5); cputs("║  2) One Angle (CORDIC) ║");
  115.   gotoxy(26, 6); cputs("║                        ║");
  116.   gotoxy(26, 7); cputs("║  3) List Series        ║");
  117.   gotoxy(26, 8); cputs("║                        ║");
  118.   gotoxy(26, 9); cputs("║  4) Statistics         ║");
  119.   gotoxy(26,10); cputs("║                        ║");
  120.   gotoxy(26,11); cputs("║  5) Time Test          ║");
  121.   gotoxy(26,12); cputs("║                        ║");
  122.   gotoxy(26,13); cputs("║  6) Quit               ║");
  123.   gotoxy(26,14); cputs("║                        ║");
  124.   gotoxy(26,15); cputs("║  Enter choice :        ║");
  125.   gotoxy(26,16); cputs("╚════════════════════════╝");
  126.  
  127.   textattr(RED);
  128.   gotoxy(43, 3); putch('D');
  129.   gotoxy(43, 5); putch('C');
  130.   gotoxy(32, 7); putch('L');
  131.   gotoxy(32, 9); putch('S');
  132.   gotoxy(32,11); putch('T');
  133.   gotoxy(32,13); putch('Q');
  134.  
  135.   gotoxy(46, 15);           /* put cursor inside box */
  136.   textattr(ti.attribute);   /* restore default text color */
  137.   return(getch());          /* get char from user, return to main() */
  138. }
  139.  
  140. void SingleAngleDegree(void)
  141. /*
  142.   USE : Calculate sin/cos for single angle, in degrees.
  143.   NOTE: Also compares with actual values from C library functions.
  144. */
  145. {
  146.   WORD   theta;      /* user-entered angle, in degrees */
  147.   int    sinTheta;   /* calculated sin in CORDIC units */
  148.   int    cosTheta;   /* calculated cos in CORDIC units */
  149.   double dSin;       /* error in CORDIC calculation */
  150.   double dCos;       /* error in CORDIC calculation */
  151.  
  152.   gotoxy(25, 20);
  153.   printf("Enter angle, in degrees : ");
  154.   scanf("%u", &theta);
  155.  
  156.   SinCos(DEG_TO_CORDIC(theta), &sinTheta, &cosTheta);
  157.   dSin = sin(DEG_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
  158.   dCos = cos(DEG_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
  159.   gotoxy(18, 22);
  160.   printf("%u deg : dSin = %8.5f   dCos = %8.5f", theta, dSin, dCos);
  161.   gotoxy(24, 25);
  162.   printf("Press a key to continue ......");
  163.   getch();
  164. }
  165.  
  166. void SingleAngleCordic(void)
  167. /*
  168.   USE : Calculate sin/cos for single angle, in CORDIC units.
  169.   NOTE: Also compares with actual values from C library functions.
  170. */
  171. {
  172.   WORD   theta;      /* user-entered angle, in CORDIC units */
  173.   int    sinTheta;   /* calculated sin in CORDIC units */
  174.   int    cosTheta;   /* calculated cos in CORDIC units */
  175.   double dSin;       /* error in CORDIC calculation */
  176.   double dCos;       /* error in CORDIC calculation */
  177.  
  178.   gotoxy(22, 20);
  179.   printf("Enter angle, in CORDIC units : ");
  180.   scanf("%u", &theta);
  181.  
  182.   SinCos(theta, &sinTheta, &cosTheta);
  183.   dSin = sin(CORDIC_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
  184.   dCos = cos(CORDIC_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
  185.   gotoxy(18, 22);
  186.   printf("%u CORDIC : dSin = %8.5f   dCos = %8.5f", theta, dSin, dCos);
  187.   gotoxy(24, 25);
  188.   printf("Press a key to continue ......");
  189.   getch();
  190. }
  191.  
  192. void ListSeries(void)
  193. /*
  194.   USE : Calculate sin/cos for series of values (0 deg - 89 deg).
  195.   NOTE: Also compares with actual values from C library functions.
  196. */
  197. {
  198.   WORD   theta;      /* increment from 0 to 89 (degrees) */
  199.   int    sinTheta;   /* calculated sin in CORDIC units */
  200.   int    cosTheta;   /* calculated cos in CORDIC units */
  201.   double dSin;       /* error in CORDIC calculation */
  202.   double dCos;       /* error in CORDIC calculation */
  203.  
  204.   clrscr();
  205.   gotoxy(14,1); printf("╔═══════════════════════════════════════════════╗");
  206.   gotoxy(14,2); printf("║   Press <SPACE> to continue, <ESC> to quit.   ║");
  207.   gotoxy(14,3); printf("╚═══════════════════════════════════════════════╝");
  208.   gotoxy(1, 5);
  209.  
  210.   for (theta = 0; theta < 90; theta++)
  211.     {
  212.     SinCos(DEG_TO_CORDIC(theta), &sinTheta, &cosTheta);
  213.     dSin = sin(DEG_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
  214.     dCos = cos(DEG_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
  215.     printf("%3u deg : dSin = %8.5f   dCos = %8.5f\n", theta, dSin, dCos);
  216.     if (getch() == ESC) return;
  217.     }
  218. }
  219.  
  220. void CalcStatistics(void)
  221. /*
  222.   USE : Calculate average error and worst error for all angles.
  223.   NOTE: Get worstError = 0.00064, avgError = 0.00011 for NBITS = 14
  224.         This is 13+ bits of precision for the average.
  225. */
  226. {
  227.   WORD   theta;      /* to index thru all angles, in CORDIC units */
  228.   double thetaRad;   /* theta in radians */
  229.   int    sinTheta;   /* calculated sin in CORDIC units */
  230.   int    cosTheta;   /* calculated cos in CORDIC units */
  231.   double dSin;       /* error in CORDIC calculation (absVal) */
  232.   double dCos;       /* error in CORDIC calculation (absVal) */
  233.   double accumError; /* accumulated error between CORDIC/actual sin/cos */
  234.   double avgError;   /* average error per sin/cos */
  235.   double worstError; /* worst error for all sin/cos */
  236.  
  237.   gotoxy(25,18); printf("╔══════════════════════════╗");
  238.   gotoxy(25,19); printf("║   Press <ESC> to quit.   ║");
  239.   gotoxy(25,20); printf("╚══════════════════════════╝");
  240.   gotoxy(1, 21);
  241.  
  242.   worstError = 0.0;
  243.   accumError = 0.0;
  244.  
  245.   /* Update worstError and accumError as progress thru entire series. */
  246.   for (theta = 0; theta < CordicBase; theta++)
  247.     {
  248.     SinCos(theta, &sinTheta, &cosTheta);
  249.     thetaRad = CORDIC_TO_RADIAN(theta);
  250.     dSin = fabs(sin(thetaRad) - (double) sinTheta / CordicBase);